﻿#include "unrealircd.h"

/**
 * 使用秒嘀科技的接口来实现发送短信
 * 
 */

typedef struct PhoneSMS PhoneSMS;

CMD_FUNC(cmd_phoneVerification);
void SendRegistSMS(Client *client ,char * phoneNumber,int sendType);
char **get_sms_head(int *head_num,char * Authorization,char * region,char *  RequestTimestamp,int data_length);
HTTPREQUESTSUCCESSCALLBACK(sendSmsSuccessCallfunc);
HTTPREQUESTFAILCALLBACK(sendSmsfaileCallfunc);

struct PhoneSMS{
	char *phone;
	char *code;
	int sendType;
};
IMConfigureSave send_Phone_sms_configure_save;

ModuleHeader MOD_HEADER
= {
	"third/tencentPhoneSMS",
	"1.1",
	"This module will send phone message ",
	"waitch",
	"unrealircd-5",
};


MOD_TEST(){
    MARK_AS_OFFICIAL_MODULE(modinfo);
	EfunctionAddVoid(modinfo->handle, EFUNC_PHONE_SMS, SendRegistSMS);
    return MOD_SUCCESS;
}

MOD_INIT()
{
	send_Phone_sms_configure_save.configure_name=NULL;
	send_Phone_sms_configure_save.configure_value=NULL;
	send_Phone_sms_configure_save.next=NULL;
	

	return MOD_SUCCESS;
}

MOD_LOAD()
{
	return MOD_SUCCESS;
}

MOD_UNLOAD()
{
	return MOD_SUCCESS;
}



/**
 * 发送注册手机验证码
 * @param[in] phoneNumber:手机号
 */
void SendRegistSMS(Client *client ,char * phoneNumber,int sendType){
	
	IMConfigureSave *secret_id=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SECRET_ID");
	if(!secret_id){
		sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SECRET_ID");
		return;
	}
	IMConfigureSave *secret_key=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SECRET_KEY ");
	if(!secret_key){
		sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SECRET_KEY ");
		return;
	}
	IMConfigureSave *smsSdkAppId=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SMS_SDK_APPID");
	if(!smsSdkAppId){
		sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SMS_SDK_APPID");
		return;
	}
    IMConfigureSave *SignName=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SIGN_NAME");
	if(!SignName){
		sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SIGN_NAME");
		return;
	}
    IMConfigureSave *templateId=NULL;
    switch (sendType)
    {
    case SMS_STATUS_REGISTER:
			templateId=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SMS_REG_TEMPLATE_ID");
            if(!templateId){
                sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SMS_REG_TEMPLATE_ID");
                return;
            }
			break;
		case SMS_STATUS_LOGIN:
			templateId=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SMS_LOGIN_TEMPLATE_ID");
            if(!templateId){
                sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SMS_LOGIN_TEMPLATE_ID");
                return;
            }
			break;
        case SMS_STATUS_RESET_PASSWORD:
			templateId=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SMS_RPASS_TEMPLATE_ID");
            if(!templateId){
                sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SMS_RPASS_TEMPLATE_ID");
                return;
            }
			break;
		case SMS_STATUS_DELETE:
		default:
            templateId=D_FindImConfigureSaveNode(&send_Phone_sms_configure_save,"TENCENT_SMS_REG_TEMPLATE_ID");
            if(!templateId){
                sendnumeric(client, CONFIGUREFAILEBYLACKMESSAGE, "PHONEVERIFICATION","TENCENT_SMS_REG_TEMPLATE_ID");
                return;
            }
    }

    char * service="sms";
    char * host = "sms.tencentcloudapi.com";
    char * region = "ap-guangzhou";
    char * action = "SendSms";
    char * version = "2021-01-11";
    int64_t timestamp = time(NULL);
    char *date = getYearMonthDayTimeChar(timestamp);
    
    // ************* 步骤 1：拼接规范请求串 *************
    char * httpRequestMethod = "POST";
    char * canonicalUri = "/";
    char * canonicalQueryString = "";
    char canonicalHeaders_[1024] = "content-type:application/json\nhost:";
    char * canonicalHeaders = canonicalHeaders_;
    strcat(canonicalHeaders_,host);
    strcat(canonicalHeaders_,"\n");
    char * signedHeaders = "content-type;host";
    char *param=random_digist(6);
    cJSON * root = cJSON_CreateObject();
    char ** PhoneNumbers=safe_alloc(sizeof(char *));
    char ** ParamNumbers=safe_alloc(sizeof(char *));
    PhoneNumbers[0] = phoneNumber;
    ParamNumbers[0] = param;
    cJSON * PhoneNumberSet=cJSON_CreateStringArray(PhoneNumbers,1);
    cJSON * ParamNumberSet=cJSON_CreateStringArray(ParamNumbers,1);
    cJSON_AddItemToObject(root, "PhoneNumberSet", PhoneNumberSet);
    cJSON_AddItemToObject(root, "TemplateParamSet", ParamNumberSet);
    cJSON_AddStringToObject(root,"SmsSdkAppId",smsSdkAppId->configure_value);
    cJSON_AddStringToObject(root,"TemplateId",templateId->configure_value);
    cJSON_AddStringToObject(root,"SignName",SignName->configure_value);
    char * payload = cJSON_PrintUnformatted(root);
    char *data=safe_alloc(strlen(payload)+10);
    strcpy(data,payload);
    cJSON_Delete(root);
    safe_free(ParamNumbers);
    safe_free(PhoneNumbers);
    char * hashedRequestPayload = sha256Hex(data);
    char * canonicalRequest=safe_alloc(sizeof(char)*1024);
    canonicalRequest[0]='\0';
    strcat(canonicalRequest,httpRequestMethod);
    strcat(canonicalRequest,"\n");
    strcat(canonicalRequest,canonicalUri);
    strcat(canonicalRequest,"\n");
    strcat(canonicalRequest,canonicalQueryString);
    strcat(canonicalRequest,"\n");
    strcat(canonicalRequest,canonicalHeaders);
    strcat(canonicalRequest,"\n");
    strcat(canonicalRequest,signedHeaders);
    strcat(canonicalRequest,"\n");
    strcat(canonicalRequest,hashedRequestPayload);

    safe_free(hashedRequestPayload);
    ircd_log(LOG_ERROR,"canonicalRequest:%s",canonicalRequest);
    // ************* 步骤 2：拼接待签名字符串 *************
    char *  algorithm = "TC3-HMAC-SHA256";
    char *  RequestTimestamp = int64_to_string(timestamp);
    char credentialScope[1024]="";
    strcat(credentialScope,date);
    strcat(credentialScope,"/");
    strcat(credentialScope,service);
    strcat(credentialScope,"/tc3_request");
    char *  hashedCanonicalRequest = sha256Hex(canonicalRequest);
    char stringToSign[1024]="";
    strcat(stringToSign,algorithm);
    strcat(stringToSign,"\n");
    strcat(stringToSign,RequestTimestamp);
    strcat(stringToSign,"\n");
    strcat(stringToSign,credentialScope);
    strcat(stringToSign,"\n");
    strcat(stringToSign,hashedCanonicalRequest);

    safe_free(canonicalRequest);
    
    ircd_log(LOG_ERROR,"stringToSign:%s",stringToSign);
    // ************* 步骤 3：计算签名 ***************
    char * kkey = safe_alloc(sizeof(char)*1024);
    kkey[0]='\0';
    strcat(kkey,"TC3");
    strcat(kkey,secret_key->configure_value);
    int kDateLength=0;
    char * kDate = hmacSha256(kkey,strlen(kkey), date,strlen(date),&kDateLength);
    ircd_log(LOG_ERROR,"kDate:%s",HexEncode(kDate,kDateLength));
    int kServiceLength=0;
    char * kService = hmacSha256(kDate,kDateLength, service,strlen(service),&kServiceLength);
    ircd_log(LOG_ERROR,"kService:%s",HexEncode(kService,kServiceLength));
    int kSigningLength=0;
    char * kSigning = hmacSha256(kService,kServiceLength, "tc3_request",strlen("tc3_request"),&kSigningLength);
    ircd_log(LOG_ERROR,"kSigning:%s",HexEncode(kService,kSigningLength));
    int _signatureLength=0;
    char * _signature=hmacSha256(kSigning,kSigningLength, stringToSign,strlen(stringToSign),&_signatureLength);
    char * signature = HexEncode(_signature,_signatureLength);

    safe_free(kkey);
    safe_free(kDate);
    safe_free(kService);
    safe_free(kSigning);
    safe_free(_signature);
    
    ircd_log(LOG_ERROR,"signature:%s",signature);
    // ************* 步骤 4：拼接 Authorization *************
    char authorization[1024]="";
    strcat(authorization,algorithm);
    strcat(authorization," Credential=");
    strcat(authorization,secret_id->configure_value);
    strcat(authorization,"/");
    strcat(authorization,credentialScope);
    strcat(authorization,", SignedHeaders=");
    strcat(authorization,signedHeaders);
    strcat(authorization,", Signature=");
    strcat(authorization,signature);

    safe_free(signature);
    ircd_log(LOG_ERROR,"authorization:%s",authorization);

	ircd_log(LOG_ERROR,"sendSMS,data:%s",data);
    //请求腾讯短信的api
	
	HttpRequestData * requestdata = malloc(sizeof(HttpRequestData));
	char *url="https://sms.tencentcloudapi.com";

    safe_strdup(requestdata->url,url);
    int data_length=strlen(data);
    ircd_log(LOG_ERROR,"data_length:%d",data_length);
    safe_strdup(requestdata->data,data);
	PhoneSMS *sms_data=safe_alloc(sizeof(PhoneSMS));
	safe_strdup(sms_data->phone,phoneNumber);
	safe_strdup(sms_data->code,param);
	sms_data->sendType=sendType;
	requestdata->userPoint = sms_data;
    requestdata->client=client;
	requestdata->requestType = 1;
	requestdata->head = get_sms_head(&(requestdata->head_num),authorization,region,RequestTimestamp,data_length);
	requestdata->successfinishCallFun = sendSmsSuccessCallfunc;
	requestdata->failefinishCallFun = sendSmsfaileCallfunc;
	add_httpRequestReady(requestdata);
    safe_free(RequestTimestamp);
    safe_free(param);
    safe_free(date);
}

char **get_sms_head(int *head_num,char * Authorization,char * region,char *  RequestTimestamp,int data_length){
	*head_num = 7;
	char **head = malloc((*head_num) * sizeof(char *));
    for(int i=0;i<(*head_num);++i){
        head[i] = NULL;
    }
    safe_strdup(head[0],"Content-type: application/json");
    safe_strdup(head[1],"Host: sms.tencentcloudapi.com");
    safe_strdup(head[2],"X-TC-Action: SendSms");
    safe_strdup(head[3],"X-TC-Version: 2021-01-11");
    head[4]=safe_alloc(100);
    head[4][0]='\0';
    strcat(head[4],"X-TC-Timestamp: ");
    strcat(head[4],RequestTimestamp);

    head[5]=safe_alloc(100);
    head[5][0]='\0';
    strcat(head[5],"X-TC-Region: ");
    strcat(head[5],region);

    head[6]=safe_alloc(1024);
    strcat(head[6],"Authorization: ");
    strcat(head[6],Authorization);

	return head;
}

HTTPREQUESTSUCCESSCALLBACK(sendSmsSuccessCallfunc){
	PhoneSMS *user_data=(PhoneSMS *)data;
	cJSON *root,*Response;
	char *error_message=NULL,*respCode;
	root = cJSON_Parse(requestData->response);
    char * p=cJSON_PrintUnformatted(root);
    char * p_s=safe_alloc(strlen(p));
    strcpy(p_s,p);
	ircd_log(LOG_ERROR,"sendSmsSuccessCallfunc,response:%s",p_s);
	switch (httpCode)
	{
	case 200://是否成功发送
		Response=cJSON_GetObjectItem(root, "Response");
		if(!Response){
			sendSmsfaileCallfunc(requestData,client,data);
			break;
		}
		cJSON *SendStatusSet=cJSON_GetObjectItem(Response,"SendStatusSet");
        if(SendStatusSet==NULL){
            cJSON *error=cJSON_GetObjectItem(Response,"Error");
            cJSON *code = cJSON_GetObjectItem(error,"Code");
            cJSON *message = cJSON_GetObjectItem(error,"Message");
            char * code_s=safe_alloc(strlen(code->valuestring)+1);
            strcpy(code_s,code->valuestring);
            char * message_s=safe_alloc(strlen(message->valuestring)+1);
            strcpy(message_s,message->valuestring);
            ircd_log(LOG_ERROR,"tencent sms send faile code:%s,message:%s",code_s,message_s);
			sendSmsfaileCallfunc(requestData,client,data);
			break;
        }
        if(cJSON_GetArraySize(SendStatusSet)!=1){
            sendSmsfaileCallfunc(requestData,client,data);
			break;
        }
        cJSON *SendStatus=cJSON_GetArrayItem(SendStatusSet,0);
		if(SendStatus==NULL){
            ircd_log(LOG_ERROR,"SendStatus==NULL");
            sendSmsfaileCallfunc(requestData,client,data);
			break;
        }
        cJSON *code = cJSON_GetObjectItem(SendStatus,"Code");
        cJSON *message = cJSON_GetObjectItem(SendStatus,"Message");
        

		if(strcmp(code->valuestring,"Ok")){
            char * code_s=safe_alloc(strlen(code->valuestring)+1);
            strcpy(code_s,code->valuestring);
            char * message_s=safe_alloc(strlen(message->valuestring)+1);
            strcpy(message_s,message->valuestring);
			ircd_log(LOG_ERROR,"tencent sms send faile code:%s,message:%s",code_s,message_s);
			sendSmsfaileCallfunc(requestData,client,data);
			break;
		}
		//将数据存储到数据库中
		D_im_sms *sms_data=db_createImSMS();
		safe_strdup(sms_data->code,user_data->code);
		safe_strdup(sms_data->contactvalue,user_data->phone);
		sms_data->sms_channel=safe_alloc(sizeof(int));
		*(sms_data->sms_channel)=SMS_MODE_PHONE;
		sms_data->sms_type=safe_alloc(sizeof(int));
		*(sms_data->sms_type)=user_data->sendType;
		sms_data->used=safe_alloc(sizeof(int));
		*(sms_data->used)=0;
		sms_data->valid_time=safe_alloc(sizeof(D_TimeStamp));
		D_getCurrectTime(sms_data->valid_time);
		int insertStatus=0;
		char insert_error_message[200]="";
		insertImSms(sms_data,&insertStatus,insert_error_message);
        db_D_ImSMSFree(sms_data,insertStatus);
		if(insertStatus==-1){
			ircd_log(LOG_ERROR, "insert im_sms error:%s", insert_error_message);
			sendSmsfaileCallfunc(requestData,client,data);
			break;
		}
		sendnumeric(client, SMSSENDSUCCESS, user_data->phone);
		break;
	default://创建失败
        {
            cJSON *response_json = cJSON_GetObjectItem(root, "respDesc");
            if(!response_json){
                safe_strdup(error_message,"unknown error message");
            }
            else if(response_json->valuestring){
                error_message=response_json->valuestring;
            }
            else{
                error_message=cJSON_PrintUnformatted(response_json);
            }
            ircd_log(LOG_ERROR, "sendSMS is error and error %s", error_message);
            sendSmsfaileCallfunc(requestData,client,data);
            break;
        }
	}

	cJSON_Delete(root);
}

HTTPREQUESTFAILCALLBACK(sendSmsfaileCallfunc){
	PhoneSMS *user_data=(PhoneSMS *)data;
	sendnumeric(client, SMSSENDFAILE, user_data->phone);
}